﻿using SmallGeo;
using NUnit.Framework;
using Shouldly;
using DotNetCommon.Extensions;
using System.Linq;
using System.Diagnostics;
using System.Numerics;

namespace SmallGeoTests
{
    [TestFixture]
    internal class Test1
    {
        /// <summary>
        /// <code>
        ///               ↑
        ///          0←─│── ⑤
        ///        ↙     │   ↗
        ///      ①--→②    ╱
        ///          ↙    ╱
        ///        ③--→④
        /// </code>
        /// </summary>
        [Test]
        public void Test()
        {
            var points = new List<Vector3d>
            {
                new Vector3d(0, 0, 0),
                new Vector3d(0,0,1),
                new Vector3d(1,0,1),
                new Vector3d(1,0,2),
                new Vector3d(2,0,2),
                new Vector3d(2,0,0),
            };
            var v = Util.GetPolygonNormal(points);
            v.IsNearlySame(new Vector3d(0, 1, 0)).ShouldBeTrue();
        }

        [Test]
        public void Test2()
        {
            /*
             *      a-------@
             *     /'\     /|
             *    / ' \   / |
             *   /  '  \ /  |
             *  @---'---d   |
             *  |   b---|-- @
             *  |  / \  |  /  
             *  | /   \ | /
             *  @-------c
             *
             */
            var points = new List<Vector3d>
            {
                new Vector3d(0,1,0),//a
                new Vector3d(0,0,0),//b
                new Vector3d(1,0,1),//c
                new Vector3d(1,1,1),//d
            };
            //以 c 为原点, cb/2 方向为x轴, cd 方向为y轴,
            var points_2d = Util.ProjectTo2d(points, new Vector3d(1, 0, 1), new Vector3d(-0.5, 0, -0.5), new Vector3d(0, 1, 0));
            points_2d = points_2d.Select(i => i.Round(4)).ToList();
            points_2d.ToJson().ShouldBe("[{\"X\":2,\"Y\":1},{\"X\":2,\"Y\":0},{\"X\":0,\"Y\":0},{\"X\":0,\"Y\":1}]");

            var points_3d = Util.UnProjectTo3d(points_2d, new Vector3d(1, 0, 1), new Vector3d(-0.5, 0, -0.5), new Vector3d(0, 1, 0));
            points_3d = points_3d.Select(i => i.Round(4)).ToList();
            points_3d.ToJson().ShouldBe("[{\"X\":0,\"Y\":1,\"Z\":0},{\"X\":0,\"Y\":0,\"Z\":0},{\"X\":1,\"Y\":0,\"Z\":1},{\"X\":1,\"Y\":1,\"Z\":1}]");
        }

        /// <summary>
        /// ceshi <image url="https://ts1.cn.mm.bing.net/th/id/R-C.e08392bd0410aa8d5e6791fc09af9555?rik=ntSNg5tIhH2RgA&riu=http%3a%2f%2fsnowcoal.com%2fIMAGES_7550%2f201501%2f14213504964207.jpg&ehk=jp9CsE%2fkp4QF%2bX6UGr66f9TAXB1WGMKvkSe57R0RiDM%3d&risl=&pid=ImgRaw&r=0" />
        /// </summary>
        [Test]
        public void Test3()
        {
            /*
             * 
             *  o-------0---------x
             *  |   |  /|\  |   
             *  |-----/---\--
             *  |   |/  |  \|   
             *  |---1-------4
             *  |   |\  |   |  
             *  |-----\------
             *  |   |  \|   |  
             *  |-------2---3
             *  |
             *  z
             */

            var points = new List<Vector3d>
            {
                new Vector3d (2,0,0),
                new Vector3d (1,0,2),
                new Vector3d (2,0,4),
                new Vector3d (3,0,4),
                new Vector3d (3,0,2),
            };
            var (uvs, box, origin, u, v) = Util.GetBoxAndUVs(points);
            uvs = uvs.Select(i => i.Round(4)).ToList();
            box = box.Select(i => i.Round(4)).ToList();
            origin = origin.Round(4);
            u = u.Round(4);
            v = v.Round(4);

            uvs.ToJson().ShouldBe("[{\"X\":0,\"Y\":0},{\"X\":0.625,\"Y\":0},{\"X\":1,\"Y\":0.6667},{\"X\":0.875,\"Y\":1},{\"X\":0.375,\"Y\":0.6667}]");
            box.ToJson().ShouldBe("[{\"X\":2,\"Y\":0,\"Z\":0},{\"X\":0.4,\"Y\":0,\"Z\":3.2},{\"X\":2.8,\"Y\":0,\"Z\":4.4},{\"X\":4.4,\"Y\":0,\"Z\":1.2}]");
            origin.ToJson().ShouldBe("{\"X\":2,\"Y\":0,\"Z\":0}");
            u.ToJson().ShouldBe("{\"X\":-1.6,\"Y\":0,\"Z\":3.2}");
            v.ToJson().ShouldBe("{\"X\":2.4,\"Y\":-0,\"Z\":1.2}");

            //指定uv方向
            (uvs, box, origin, u, v) = Util.GetBoxAndUVs(points, new Vector3d(1, 0, 0), new Vector3d(0, 0, 1));
            uvs = uvs.Select(i => i.Round(4)).ToList();
            box = box.Select(i => i.Round(4)).ToList();
            origin = origin.Round(4);
            u = u.Round(4);
            v = v.Round(4);

            uvs.ToJson().ShouldBe("[{\"X\":0.5,\"Y\":0},{\"X\":0,\"Y\":0.5},{\"X\":0.5,\"Y\":1},{\"X\":1,\"Y\":1},{\"X\":1,\"Y\":0.5}]");
            box.ToJson().ShouldBe("[{\"X\":1,\"Y\":0,\"Z\":0},{\"X\":3,\"Y\":0,\"Z\":0},{\"X\":3,\"Y\":0,\"Z\":4},{\"X\":1,\"Y\":0,\"Z\":4}]");
            origin.ToJson().ShouldBe("{\"X\":1,\"Y\":0,\"Z\":0}");
            u.ToJson().ShouldBe("{\"X\":2,\"Y\":0,\"Z\":0}");
            v.ToJson().ShouldBe("{\"X\":0,\"Y\":0,\"Z\":4}");
        }

        [Test]
        public void Test4()
        {
            var v1 = new Vector2d(1, 0);
            var v2 = new Vector2d(0, 1);
            var d = Util.Cross(v1, v2);
            var d2 = Util.Cross(v2, v1);
        }

        [Test]
        public void Test5()
        {
            //      2----3
            //      |    |
            // 0----1    4
            // |         |
            // 6---------5
            var points = new List<Vector2d>
            {
                new Vector2d (0, 0),
                new Vector2d (1, 0),
                new Vector2d (1, 1),
                new Vector2d (2, 1),
                new Vector2d (2, 0),
                new Vector2d (2, -1),
                new Vector2d (0, -1),
            };
            var radians = Util.GetPolygonRadians(points);
            var degrees = radians.Select(i => i.ToDegree()).ToList();
            degrees.ToJson().ShouldBe("[90,270,90,90,180,90,90]");

            //      4----3
            //      |    |
            // 6----5    2
            // |         |
            // 0---------1
            points.Reverse();
            radians = Util.GetPolygonRadians(points);
            degrees = radians.Select(i => i.ToDegree()).ToList();
            degrees.ToJson().ShouldBe("[90,90,180,90,90,270,90]");
        }

        [Test]
        public void Test_GetSignedArea()
        {
            //      2----3
            //      |    |
            // 0----1    4
            // |         |
            // 6---------5
            var points = new List<Vector2d>
            {
                new Vector2d (0, 0),
                new Vector2d (1, 0),
                new Vector2d (1, 1),
                new Vector2d (2, 1),
                new Vector2d (2, 0),
                new Vector2d (2, -1),
                new Vector2d (0, -1),
            };
            var area = Util.GetSignedArea(points);
            area.ShouldBe(-3);

            //      4----3
            //      |    |
            // 6----5    2
            // |         |
            // 0---------1
            points.Reverse();
            area = Util.GetSignedArea(points);
            area.ShouldBe(3);

            // 原定在o:
            //           2----3
            //           |    |
            //      0----1    4
            //      |         |
            // o    6---------5
            points.Reverse();
            points.Select(i => i + new Vector2d(1, 1));
            area = Util.GetSignedArea(points);
            area.ShouldBe(-3);
        }

        [Test]
        public void PointWithPolygon()
        {
            // 
            // 2-------1
            // |       |
            // |   .   |
            // |       |
            // 3-------0
            // 
            var point = new Vector2d(0, 0);
            var polygon = new List<Vector2d>
            {
                new Vector2d(1,-1),
                new Vector2d(1,1),
                new Vector2d(-1,1),
                new Vector2d(-1,-1),
            };
            var result = Util.CalculatePointWithPolygon(point, polygon);
            result.IsInside().ShouldBe(true);

            // 
            // 2-----1
            // |     |
            // 3  .  |
            //  \    |
            //   4---0
            // 
            point = new Vector2d(0, 0);
            polygon = new List<Vector2d>
            {
                new Vector2d(1,-1),
                new Vector2d(1,1),
                new Vector2d(-1,1),
                new Vector2d(-1,0),
                new Vector2d(0,-1),
            };
            result = Util.CalculatePointWithPolygon(point, polygon);
            result.IsInside().ShouldBe(true);

            // 3的位置是原点
            // 2---p---1
            // |       |
            // |       |
            // 3-------0
            // 
            point = new Vector2d(1, 2);
            polygon = new List<Vector2d>
            {
                new Vector2d(2,0),
                new Vector2d(2,2),
                new Vector2d(0,2),
                new Vector2d(0,0),
            };
            result = Util.CalculatePointWithPolygon(point, polygon);
            result.IsOn().ShouldBe(true);
            result.Flag.ShouldBe(EnumPointWithPolygon.IsOnEdge);
            result.PointIndex.ShouldBe(1);
            result.CrossPoint.ShouldBe(new Vector2d(1, 2));

        }

        [Test]
        public void Test_Tri()
        {
            /* 0的位置是原点
             * 5---------4
             * |         |
             * |    2----3
             * |    |
             * 0----1
             */
            var points = new List<Vector2d>()
            {
                new Vector2d (0,0),
                new Vector2d (1,0),
                new Vector2d (1,1),
                new Vector2d (2,1),
                new Vector2d (2,2),
                new Vector2d (0,2),
            };

            var tris = Util.Triangle(points);
            tris.ToJson().ShouldBe("[0,1,2,2,3,4,2,4,5,2,5,0]");

            /* 0的位置是原点
             *             2
             *           * *
             *         3   *
             *       *     *
             *     4       *
             *   *         *
             * 0 * * * * * 1
             */
            points = new List<Vector2d>()
            {
                new Vector2d (0,0),
                new Vector2d (3,0),
                new Vector2d (3,3),
                new Vector2d (2,2),
                new Vector2d (1,1),
            };
            tris = Util.Triangle(points);
            tris.ToJson().ShouldBe("[1,2,3,1,3,4,1,4,0]");


            /*
             * 0的位置是原点
             * 1-----2     5-----6     9-----10
             * |     |     |     |     |     |
             * |     |     |     |     |     |
             * |     3-----4     7-----8     11
             * |                             |
             * |                             |
             * 0-----------------------------12
             */
            points = new List<Vector2d>()
            {
                new Vector2d (0,0),
                new Vector2d (0,2),
                new Vector2d (1,2),
                new Vector2d (1,1),
                new Vector2d (2,1),
                new Vector2d (2,2),
                new Vector2d (3,2),
                new Vector2d (3,1),
                new Vector2d (4,1),
                new Vector2d (4,2),
                new Vector2d (5,2),
                new Vector2d (5,1),
                new Vector2d (5,0),
            };
            tris = Util.Triangle(points);
            tris.ToJson().ShouldBe("[0,1,2,0,2,3,0,3,4,4,5,6,4,6,7,8,9,10,8,10,11,8,11,12,8,12,0,0,4,7,0,7,8]");
        }

        [Test]
        public void Test_CalculatePointWithLineSegment()
        {
            /*
             *          p(0,0.5)
             *          
             *   p0-----0-----p1
             * (-1,0)       (1,0)
             */
            var p = new Vector2d(0, 0.5);
            var p0 = new Vector2d(-1, 0);
            var p1 = new Vector2d(1, 0);

            var ret = Util.CalculatePointWithLineSegment(p, p0, p1, 1);
            ret.IsOnLine().ShouldBe(true);
            ret.IsOutLine().ShouldBe(false);
            ret.CrossPoint.ShouldBe(Vector2d.Zero);
            ret.PointIndex.ShouldBe(0);

            /*
             *         p(0,0.5)
             *  
             * 0-------p0-------p1
             *       (1,0)    (2,0)
             */
            p = new Vector2d(0, 0.5);
            p0 = new Vector2d(1, 0);
            p1 = new Vector2d(2, 0);

            ret = Util.CalculatePointWithLineSegment(p, p0, p1, 1);
            ret.IsOnLine().ShouldBe(false);
            ret.IsOutLine().ShouldBe(true);
            ret.CrossPoint.ShouldBe(Vector2d.Zero);
            ret.PointIndex.ShouldBe(0);
        }

        [Test]
        public void Test_IntersectLineOnLine()
        {
            /*             (1,1) 
             *           *
             *   line2 *
             *       *
             *     *
             *   0  *  *  *  (1,0)
             *        line1
             */
            var line1 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(0, 1));
            var line2 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(1, 1));
            var p = Util.IntersectLineAndLine(line1, line2);
            p.ShouldBe(new Vector2d(0, 0));

            /*
             * 平行
             *      line2
             * 1----------
             * |
             * |
             * |    line1
             * 0----------1
             */
            line1 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(1, 0));
            line2 = new LineSegment2d(new Vector2d(0, 1), new Vector2d(1, 1));
            var p2 = Util.IntersectLineAndLine(line1, line2);
            p2.ShouldBe(new Vector2d(0, 0));

            /*               (1,2)
             *             *
             *           * line2
             *         *
             *  (0,1)* 
             *       *
             *       *
             *       0 * * * (1,0)
             *          line1
             */
            line1 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(1, 0));
            line2 = new LineSegment2d(new Vector2d(0, 1), new Vector2d(1, 2));
            var p3 = Util.IntersectLineAndLine(line1, line2);
            p3.ShouldBe(new Vector2d(-1, 0));

        }

        [Test]
        public void Test_IntersectLineSegmentOnLineSegment()
        {
            /*             (1,1) 
             *           *
             *   line2 *
             *       *
             *     *
             *   0  *  *  *  (1,0)
             *        line1
             */
            var line1 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(0, 1));
            var line2 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(1, 1));
            var res = Util.IntersectLineSegmentAndLineSegment(line1, line2);
            res.ShouldBe(new List<Vector2d>() { Vector2d.Zero });

            /*
             * 平行
             *      line2
             * 1----------
             * |
             * |
             * |    line1
             * 0----------1
             */
            line1 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(1, 0));
            line2 = new LineSegment2d(new Vector2d(0, 1), new Vector2d(1, 1));
            res = Util.IntersectLineSegmentAndLineSegment(line1, line2);
            res.ShouldBe(new List<Vector2d>());

            /*               (1,2)
             *             *
             *           * line2
             *         *
             *  (0,1)* 
             *       *
             *       *
             *       0 * * * (1,0)
             *          line1
             */
            line1 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(1, 0));
            line2 = new LineSegment2d(new Vector2d(0, 1), new Vector2d(1, 2));
            res = Util.IntersectLineSegmentAndLineSegment(line1, line2);
            res.ShouldBe(new List<Vector2d>());

            /*
             *      0            1           2           3
             *      x------------p-----------x-----------p
             *  line1_p0      line2_p0     line1_p1    line2_p1
             * 
             */
            line1 = new LineSegment2d(new Vector2d(0, 0), new Vector2d(2, 0));
            line2 = new LineSegment2d(new Vector2d(1, 0), new Vector2d(3, 0));
            res = Util.IntersectLineSegmentAndLineSegment(line1, line2);
            res.ShouldBe(new List<Vector2d> { new Vector2d(2, 0), new Vector2d(1, 0) });
        }

        [Test]
        public void Test_RemoveSamePoint()
        {
            /* 下面的点2将会被移除
             * 5----------------4
             * |                |
             * |                |
             * |                |
             * |                |
             * |                |
             * 0-------1-2------3
             * 
             */
            var points = new List<Vector2d>
            {
                new Vector2d (0, 0), //0
                new Vector2d (0.5, 0), //1
                new Vector2d (0.6, 0), //2
                new Vector2d (1, 0), //3
                new Vector2d (1, 1), //4
                new Vector2d (0, 1), //5
                new Vector2d (0, 0), //
            };
            Util.RemovePointNearlySame(points, 0.1);
            points.ShouldBe(new List<Vector2d>
            {
                new Vector2d (0, 0), //0
                new Vector2d (0.5, 0), //1
                //new Vector2d (0.6, 0), //2
                new Vector2d (1, 0), //3
                new Vector2d (1, 1), //4
                new Vector2d (0, 1), //5
                //new Vector2d (0, 0), //
            });
        }

        [Test]
        public void Test_RemovePointsOnLine()
        {
            /* 下面的点1和点2都将会被移除
             * 5----------------4
             * |                |
             * |                |
             * |                |
             * |                |
             * |                |
             * 0-------1-2------3
             */
            var points = new List<Vector2d>
            {
                new Vector2d (0, 0), //0
                new Vector2d (0.5, 0), //1
                new Vector2d (0.6, 0), //2
                new Vector2d (1, 0), //3
                new Vector2d (1, 1), //4
                new Vector2d (0, 1), //5
                new Vector2d (0, 0), //
            };
            Util.RemovePointNearlyOnLine(points, 0.1);
            points.ShouldBe(new List<Vector2d>
            {
                new Vector2d (0, 0), //0
                //new Vector2d (0.5, 0), //1
                //new Vector2d (0.6, 0), //2
                new Vector2d (1, 0), //3
                new Vector2d (1, 1), //4
                new Vector2d (0, 1), //5
                //new Vector2d (0, 0), //
            });

            /* 下面的点1和点2都将会被移除
             * 3----------------2
             * |                |
             * |                |
             * |                |
             * |                |
             * |                |
             * 4-------5-0------1
             */
            points = new List<Vector2d>
            {
                new Vector2d (0.6, 0), //0
                new Vector2d (1, 0), //1
                new Vector2d (1, 1), //2
                new Vector2d (0, 1), //3
                new Vector2d (0, 0), //4
                new Vector2d (0.5, 0), //5
                new Vector2d (0.6, 0), //
            };
            Util.RemovePointNearlyOnLine(points, 0.1);
            points.ShouldBe(new List<Vector2d>
            {
                //new Vector2d (0.6, 0), //0
                new Vector2d (1, 0), //1
                new Vector2d (1, 1), //2
                new Vector2d (0, 1), //3
                new Vector2d (0, 0), //4
                //new Vector2d (0.5, 0), //5
                //new Vector2d (0.6, 0), //
            });
        }

        [Test]
        public void Test_PrePen()
        {
            /*
             *       P1(new)
             *         |
             *         |
             *         |
             * 0-------x--------x------->x
             *         P0     P1(old)
             */
            var ret = Util.GetLinePerpendicular(new LineSegment2d(new Vector2d(1, 0), new Vector2d(2, 0)), true);
            ret.P0.ShouldBe(new Vector2d(1, 0));
            ret.P1.ShouldBe(new Vector2d(1, 1));

            /*
             *        P0       P1(old)
             * 0-------x--------x------->x
             *         |
             *         |
             *         |
             *        P1(new)      
             */
            ret = Util.GetLinePerpendicular(new LineSegment2d(new Vector2d(1, 0), new Vector2d(2, 0)), false);
            ret.P0.ShouldBe(new Vector2d(1, 0));
            ret.P1.ShouldBe(new Vector2d(1, -1));

            /*
             *       P0(old)    P1
             * 0-------x--------x------->x
             *                  |
             *                  |
             *                  |
             *                 P0(new)
             */
            ret = Util.GetLinePerpendicular(new LineSegment2d(new Vector2d(1, 0), new Vector2d(2, 0)), true, 1);
            ret.P0.ShouldBe(new Vector2d(2, -1));
            ret.P1.ShouldBe(new Vector2d(2, 0));

            /*
             *                P1(new)
             *                  |
             *       P0(old)    |    P1(old)
             * 0----------x-----|-----x---------->x
             *                  |
             *                  |
             *               P0(new)
             */
            ret = Util.GetLinePerpendicular(new LineSegment2d(new Vector2d(1, 0), new Vector2d(2, 0)), true, 2);
            ret.P0.ShouldBe(new Vector2d(1.5, -0.5));
            ret.P1.ShouldBe(new Vector2d(1.5, 0.5));
        }

        [Test]
        public void Test_Project()
        {
            var parapet = "[{\"X\":-137.39954,\"Y\":189.03427,\"Z\":587.1493},{\"X\":-63.743378,\"Y\":1031.9443,\"Z\":586.57104},{\"X\":104.8436,\"Y\":100,\"Z\":583.93176},{\"X\":104.8436,\"Y\":0,\"Z\":583.93176},{\"X\":-137.39954,\"Y\":0,\"Z\":587.1493}]".ToObject<List<Vector3d>>();
            var face = "[{\"X\":-203.68495,\"Y\":280,\"Z\":589.00006},{\"X\":-203.68495,\"Y\":0,\"Z\":589.00006},{\"X\":310,\"Y\":0,\"Z\":589},{\"X\":310,\"Y\":280,\"Z\":589}]".ToObject<List<Vector3d>>();

            var dir = new Vector3d(-0.99991393, 0, 0.013112084);
            var i = parapet.Select(i => Util.ProjectOnVector(i, dir)).ToList();

        }

        [Test]
        public void Test_PolygonIntersect()
        {
            /*  5             M-------------K
             *                |             |
             *                |             |
             *  4 h-----------|------g      |
             *    |           |      |      |
             *    |           |      |      |
             *  3 |     e-----|------f      |
             *    |     |     |             |
             *    |     |     |             |
             *  2 |     d-----|------c      |
             *    |           |      |      |
             *    |           |      |      |
             *  1 a-----------|------b      |
             *                |             |
             *                |             |
             *    o           N-------------J
             *          1     2      3      4
             *    
             */
            var poly1 = new List<Vector2d>
            {
                new Vector2d(0,1),//a
                new Vector2d(3,1),//b
                new Vector2d(3,2),//c
                new Vector2d(1,2),//d
                new Vector2d(1,3),//e
                new Vector2d(3,3),//f
                new Vector2d(3,4),//g
                new Vector2d(0,4),//h
            };
            var poly2 = new List<Vector2d>
            {
                new Vector2d(2,5),//M
                new Vector2d(2,0),//N
                new Vector2d(4,0),//J
                new Vector2d(4,5),//K
            };
            var ret = Util.IntersectPolygon(poly1, poly2);
            Console.WriteLine(ret);

        }

        [Test]
        public void Test99()
        {
            //var ps1 = new List<Vector2d> { new(-560.04, 1215.82), new(-549.59, 1250.1) };
            //var h1 = 0.11;
            //var c1 = FindCenter(ps1[1], ps1[0], h1);
            //var ps2 = new List<Vector2d> { new(-541.4, 362.97), new(-541.4, 1275.0) };
            //var h2 = 75.21;
            //var c2 = FindCenter(ps2[0], ps2[1], h2);
            //Console.WriteLine($"{c1},{c2}");

            var ps1 = new List<Vector2d> { new(-5.600373964465183 * 100, 12.15815942227024 * 100), new(-5.495887611584745 * 100, 12.500974649508398 * 100) };
            var h1 = 0.0011306531892909533 * 100;
            var c1 = FindCenter(ps1[1], ps1[0], h1);
            var ps2 = new List<Vector2d> { new(-541.4, 362.97), new(-541.4, 1275.0) };
            var h2 = 75.21;
            var c2 = FindCenter(ps2[0], ps2[1], h2);
            Console.WriteLine($"{c1},{c2}");

            Vector2d FindCenter(Vector2d p1, Vector2d p2, double arcHeight)
            {
                var mid1 = (p1 + p2) / 2;
                var dir = (p2 - p1).Rotate(Math.PI / 2).Normalized();
                var p3 = mid1 + dir * arcHeight;
                var dir2 = (p3 - p1).Rotate(Math.PI / 2).Normalized();

                var ret = Util.IntersectLineAndLine(new LineSegment2d(mid1, mid1 + dir * 100), new LineSegment2d((p1 + p3) / 2, (p1 + p3) / 2 + dir2 * 100));
                return ret;
            }
        }

        [Test]
        public void Test101()
        {
            var center = """{"x":5.055617916567725,"y":-3.8013798447341527}""".ToObject<Vector2d>();
            var startPos = """{"x":5.051195568929018,"y":-5.182422951681995}""".ToObject<Vector2d>();
            var end = """{"x":4.914600000000001,"y":-5.070814165200254}""".ToObject<Vector2d>();
            var start = """{"x":4.914600000000001,"y":-5.799999999999999}""".ToObject<Vector2d>();
            var line = new LineSegment2d(start, end);

            var normal = line.Direction().Rotate(Math.PI / 2);
            var line1 = new LineSegment2d(line.P0 + normal * 0.27 / 2, line.P1 + normal * 0.27 / 2);
            var line2 = new LineSegment2d(line.P0 - normal * 0.27 / 2, line.P1 - normal * 0.27 / 2);

            var rad = new LineSegment2d(center, startPos);
            Console.WriteLine("ok");

            var ps = Util.IntersectLineAndLine(line2, rad);
            var flag = Util.IsNearyLineSegmentIntersect(line2, rad);
            var flag2 = Util.IsNearyLineSegmentIntersect(line2, rad, 0.000001);
            var flag3 = Util.IsNearyLineSegmentIntersect(line2, rad, 0);
            var flag4 = Util.IsNearyLineSegmentIntersect(line2, rad, 0.01);//true
            var flag5 = Util.IsNearyLineSegmentIntersect(line2, rad, 0.001);
            Console.WriteLine("lp");
        }

        [Test]
        public void Test102()
        {
            var line = new LineSegment2d(new(492.1, 220.48), new(492.1, 81.5));
            var line2 = new LineSegment2d(new(497.63, 81.31), new(498.79, 40.75));
            var box1 = line.GetRect(12);
            var box2 = line2.GetRect(24);
            var json1 = box1.ToJson();
            var json2 = box2.ToJson();


            var _line = new LineSegment2d(new(492.1, 220.48), new(492.1, 81.5));
            var _line2 = new LineSegment2d(new(497.6277062056462, 81.31444111828112), new(498.7906775679823, 40.75));
            var _box1 = _line.GetRect(12);
            var _box2 = _line2.GetRect(24);
            var _json1 = _box1.ToJson();
            var _json2 = _box2.ToJson();

            Console.WriteLine("ok");
        }

        [Test]
        public static void Test103()
        {
            var v = Util.ProjectOnVector(new Vector2d(2, 2), new Vector2d(2, 0));
            var v2 = Util.ProjectOnVector(new Vector2d(2, 2), new Vector2d(1, 0));

            var u = Util.ProjectOnVectorUnary(new Vector2d(2, 2), new Vector2d(2, 0));
            var u2 = Util.ProjectOnVectorUnary(new Vector2d(-2, 2), new Vector2d(2, 0));
            Console.WriteLine("ok");
        }
    }
}
